import 'reflect-metadata'
function Injectable(target) {
// 这里面可以不用写任何代码，此装饰器不需要执行任何操作，仅用于生成元数据
}
@Injectable
class Gas {
  constructor(private num: number) {
    
  }
  start() {
    console.log('start gas', this.num)
  }
}
@Injectable
class Engine {
  constructor(private gas: Gas, age: number) {

  }
  start() {
    this.gas.start()
    console.log(`Engine started`)
  }
}
@Injectable
class Car {
  constructor(private engine: Engine) {
  }
  drive() {
    this.engine.start()
    console.log(`Car is running`)
  }
}

// 定义一个依赖注入容器类
class DIContainer {
  // 定义一个存储所有的服务的Map对象
  private services = new Map<string, any>()
  // 注册服务的方法，把服务的名称和实现保存到Map中
  register<T>(name: string, Service: any) {
    // 把类的名称和类的构造函数存放在Map中
    this.services.set(name, Service)
  }
  resolve<T>(name: string) {
    // 获取服务的实现类
    const Service = this.services.get(name)
    if (Service instanceof Function) {
      // Service是一个类
      // 获取实现类的构造函数参数的类型数组
      const dependencies = Reflect.getMetadata('design:paramtypes', Service)??[]
      // 递归解析所有的依赖
      const injections = dependencies.map(dependency => this.resolve(dependency.name))
      console.log(injections);
      
      // 创建并返回类的实例
      return new Service(...injections)
    } else if (Service.useFactory) {
      const { inject } = Service
      // 可能是注册的一个工厂函数
      return Service.useFactory(...inject)
    } else if (Service.useValue) {
      // 可能是一个给定的值
      return Service.useValue
    }
  }
}
// 创建一个依赖注入的容器实例
const container = new DIContainer()
container.register<Gas>('Gas', {
  provide: 'Gas',
  inject: [100],
  useFactory: (number) => {
    return new Gas(number)
  }
})
container.register<Engine>('Engine', {
  provide: 'Engine',
  useValue: new Engine(new Gas(200), 18)
})
container.register<Car>('Car', Car)
const car = container.resolve<Car>('Car')
car.drive()